package com.hissy.common.serializer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import com.caucho.hessian.io.AbstractSerializerFactory;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.HessianFactory;
import com.caucho.hessian.io.SerializerFactory;
import com.hissy.common.util.HexStringUtil;
/**
 * 基于Hession的对象序列话
 *
 * @author guankaiqiang modified hession处理BigDecimal以及SoftReference序列化问题
 */
public class HessionSerializer implements Serializer {
    public static final SerializerFactory SERIALIZER_FACTORY = new SerializerFactory();
    public static final HessianFactory HESSION_FACTORY = new HessianFactory();

    static {
        SERIALIZER_FACTORY.addFactory(new HessionBigDecimalSerializerFactory());
        SERIALIZER_FACTORY.addFactory(new HessionSoftReferenceSerializerFactory());
        HESSION_FACTORY.setSerializerFactory(SERIALIZER_FACTORY);
    }

    /**
     * 添加自定义SerializerFactory
     *
     * @param factory AbstractSerializerFactory
     */
    public void addSerializerFactory(AbstractSerializerFactory factory) {
        SERIALIZER_FACTORY.addFactory(factory);
    }

    @Override
    public String toString(Object value) {
        byte[] bytes = toBytes(value);
        return HexStringUtil.toHexString(bytes);
    }

    @Override
    public byte[] toBytes(Object value) {
        if (value == null) {
            return null;
        }
        try {
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                Hessian2Output out = null;
                try {
                    out = HESSION_FACTORY.createHessian2Output(bos);
                    out.startMessage();
                    out.writeObject(value);
                    out.completeMessage();
                    out.flush();
                    return bos.toByteArray();
                } finally {
                    if (out != null) {
                        out.close();
                        HESSION_FACTORY.freeHessian2Output(out);
                    }
                }
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
        //byte[] val = null;
        //try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
        //    AbstractHessianOutput output = null;
        //    try {
        //        output = new Hessian2Output(outputStream);
        //        output.setSerializerFactory(SERIALIZER_FACTORY);
        //        // 将对象写到流里
        //        output.writeObject(value);
        //        output.flush();
        //        val = outputStream.toByteArray();
        //    } finally {
        //        if (output != null) {
        //            output.close();
        //            HESSION_FACTORY.freeHessian2Output(output);
        //        }
        //    }
        //} catch (IOException ex) {
        //    throw new RuntimeException(ex);
        //}
        //return val;
    }

    @Override
    public <T> T toObject(String value, Class<T> clazz) {
        byte[] bytes = HexStringUtil.toByteArray(value);
        return toObject(bytes, clazz);
    }

    @Override
    public <T> T toObject(byte[] bytes, Class<T> clazz) {
        if (bytes == null) {
            return null;
        }

        try {
            try (ByteArrayInputStream bin = new ByteArrayInputStream(bytes)) {
                Hessian2Input in = null;
                try {
                    in = HESSION_FACTORY.createHessian2Input(bin);
                    in.startMessage();
                    Object value = in.readObject();
                    in.completeMessage();
                    return (T)value;
                } finally {
                    if (in != null) {
                        in.close();
                        HESSION_FACTORY.freeHessian2Input(in);
                    }
                }
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}
